package bridge

import (
	"strings"
	"sync"

	"gitee.com/tomatomeatman/golang-repository/bricks2/function/data/integerutil"
	"gitee.com/tomatomeatman/golang-repository/bricks2/function/data/stringutil"
	"gitee.com/tomatomeatman/golang-repository/bricks2/utils/app"
	"gitee.com/tomatomeatman/golang-repository/bricks2/utils/gorm"
	Log "github.com/cihub/seelog"
)

var (
	syncTablekeyMap      = map[string]*sync.Mutex{} //序列锁集合
	syncCountTablekeyMap = map[string]int{}         //序列锁引用计数值集合,当值为0时同时清理'序列锁集合'
	sDbName              string                     //数据库名
)

func init() {
	if app.IsNotCloudSystem() { //禁用桥接
		return
	}

	sDbName = app.ReadConfigKey("DbVariables", "BaseSystem", "base_system").(string)

	app.SetTableKeyServiceName("TableKey")
	app.RegisterDao("TableKey", &TableKeyDao{})
}

/**
 * 记录编号序列管理表TableKey表基本业务操作结构体
 */
type TableKeyDao struct {
	app.DaoBaseFunc
}

/**
 * 取各表(或序列)的新Id
 * @param formatLong 格式化长度(不足长度+0)
 * @param serieName 表名或序列名
 * @return
 */
func (dao TableKeyDao) GetNewId(formatLong int, serieName string) string {
	lock, ok := syncTablekeyMap[serieName]
	if !ok {
		syncTablekeyMap[serieName] = &sync.Mutex{}
		syncCountTablekeyMap[serieName] = 1 //计数值
		lock = syncTablekeyMap[serieName]
	} else {
		syncCountTablekeyMap[serieName] = syncCountTablekeyMap[serieName] + 1 //计数值
	}

	lock.Lock() //加锁

	iCount := dao.newValue(serieName)
	if iCount != 1 {
		iCount = dao.addTable(serieName)
		if iCount != 0 {
			syncCountTablekeyMap[serieName] = syncCountTablekeyMap[serieName] - 1 //计数值-1
			if syncCountTablekeyMap[serieName] < 1 {                              //计数值为0,剔除
				delete(syncCountTablekeyMap, serieName)
				delete(syncTablekeyMap, serieName)
			}

			lock.Unlock() //解锁
			return stringutil.SupplyZero(formatLong, 1)
		}

		syncCountTablekeyMap[serieName] = syncCountTablekeyMap[serieName] - 1 //计数值-1
		if syncCountTablekeyMap[serieName] < 1 {                              //计数值为0,剔除
			delete(syncCountTablekeyMap, serieName)
			delete(syncTablekeyMap, serieName)
		}

		lock.Unlock() //解锁
		return "0"    //说明是取值失败
	}

	Id := dao.findLastId(serieName)
	if Id == "0" {
		syncCountTablekeyMap[serieName] = syncCountTablekeyMap[serieName] - 1 //计数值-1
		if syncCountTablekeyMap[serieName] < 1 {                              //计数值为0,剔除
			delete(syncCountTablekeyMap, serieName)
			delete(syncTablekeyMap, serieName)
		}

		lock.Unlock() //解锁
		return "0"    //说明是取值失败
	}

	syncCountTablekeyMap[serieName] = syncCountTablekeyMap[serieName] - 1 //计数值-1
	if syncCountTablekeyMap[serieName] < 1 {                              //计数值为0,剔除
		delete(syncCountTablekeyMap, serieName)
		delete(syncTablekeyMap, serieName)
	}

	lock.Unlock() //解锁

	result := stringutil.SupplyZero(formatLong, Id)

	return result
}

/**
 * 取各表的一批新Id
 * @param formatLong 格式化长度(不足长度+0)
 * @param serieName 表名或序列名
 * @param size 数量
 * @return
 */
func (dao TableKeyDao) GetNewIds(formatLong int, serieName string, size int) []string {
	lock, ok := syncTablekeyMap[serieName]
	if !ok {
		syncTablekeyMap[serieName] = &sync.Mutex{}
		syncCountTablekeyMap[serieName] = 1 //计数值
		lock = syncTablekeyMap[serieName]
	} else {
		syncCountTablekeyMap[serieName] = syncCountTablekeyMap[serieName] + 1 //计数值
	}

	lock.Lock() //加锁

	iCount := dao.newValues(serieName, size)
	if iCount != 1 {
		iCount = dao.addTableValues(serieName, size)
	}

	if iCount != 1 {
		syncCountTablekeyMap[serieName] = syncCountTablekeyMap[serieName] - 1 //计数值-1
		if syncCountTablekeyMap[serieName] < 1 {                              //计数值为0,剔除
			delete(syncCountTablekeyMap, serieName)
			delete(syncTablekeyMap, serieName)
		}

		lock.Unlock() //解锁
		return nil    //说明是取值失败
	}

	sLastId := dao.findLastId(serieName)

	syncCountTablekeyMap[serieName] = syncCountTablekeyMap[serieName] - 1 //计数值-1
	if syncCountTablekeyMap[serieName] < 1 {                              //计数值为0,剔除
		delete(syncCountTablekeyMap, serieName)
		delete(syncTablekeyMap, serieName)
	}

	lock.Unlock() //解锁

	iLastId := integerutil.ToInt(sLastId)

	result := []string{}
	for i := 0; i < size; i++ {
		vNewId := stringutil.SupplyZero(formatLong, iLastId+i+1)
		result = append(result, vNewId)
	}

	return result
}

/**
 * 重置
 * @param serieName 表名或序列名
 * @return
 */
func (dao TableKeyDao) Reset(serieName string) string {
	iCount := dao.reset(serieName)

	if iCount < 1 {
		return "0"
	}

	return "1"
}

/**
 * 更新到新Value值
 * @param Type
 * @return
 */
func (dao TableKeyDao) newValue(serieName string) int {
	sql := "UPDATE ${BaseSystem}table_key SET Value = (Value +1) ,edition = (edition +1) WHERE Type = '#{Type}'"
	sql = strings.Replace(sql, "${BaseSystem}", sDbName, -1)
	sql = strings.Replace(sql, "#{Type}", serieName, -1)

	dbResult := gorm.Exec(sql)
	if dbResult.Error != nil {
		Log.Error("更新数据发生异常:", dbResult.Error)
		return 0
	}

	return integerutil.ToInt(dbResult.RowsAffected, 0)
}

/**
 * 取最后的id值
 * @param Value
 * @return
 */
func (dao TableKeyDao) findLastId(serieName string) string {
	sql := "SELECT Value FROM ${BaseSystem}TableKey WHERE Type = '#{Type}'"
	sql = strings.Replace(sql, "${BaseSystem}", sDbName, -1)
	sql = strings.Replace(sql, "#{Type}", serieName, -1)

	Value := "0"
	dbResult := gorm.Raw(sql).Find(&Value)
	if dbResult.Error != nil {
		Log.Error("更新数据发生异常:", dbResult.Error)
		return Value
	}

	return Value
}

/**
 * 添加表字段信息
 * @param serieName
 * @return
 */
func (dao TableKeyDao) addTable(serieName string) int {
	sql := `
	INSERT INTO ${BaseSystem}TableKey (
		Id
		,Type
		,Value
		,Rank
		,edition
	)
	SELECT
		IFNULL(MAX(Id), 0) +1
		,'#{Type}'
		,'1'
		,1
		,1
	FROM ${BaseSystem}TableKey`
	sql = strings.Replace(sql, "${BaseSystem}", sDbName, -1)
	sql = strings.Replace(sql, "#{Type}", serieName, -1)

	dbResult := gorm.Exec(sql)
	if dbResult.Error != nil {
		Log.Error("更新数据发生异常:", dbResult.Error)
		return 0
	}

	return integerutil.ToInt(dbResult.RowsAffected, 0)
}

/**
 * 更新到新的一批Value值
 * @param serieName
 * @param size
 * @return
 */
func (dao TableKeyDao) newValues(serieName string, size int) int {
	sql := `UPDATE ${BaseSystem}TableKey SET
				Value = (Value +1 + #{size})
				,edition = (edition +1 + #{size})
			WHERE Type = #{Type}`
	sql = strings.Replace(sql, "${BaseSystem}", sDbName, -1)
	sql = strings.Replace(sql, "#{size}", stringutil.ToStr(size), -1)
	sql = strings.Replace(sql, "#{Type}", serieName, -1)

	dbResult := gorm.Exec(sql)
	if dbResult.Error != nil {
		Log.Error("更新数据发生异常:", dbResult.Error)
		return 0
	}

	return integerutil.ToInt(dbResult.RowsAffected, 0)
}

/**
 * 添加表字段信息,并设置初始值
 * @param serieName
 * @param size
 * @return
 */
func (dao TableKeyDao) addTableValues(serieName string, size int) int {
	sql := `
	INSERT INTO ${BaseSystem}TableKey (
		Id
		,Type
		,Value
		,Rank
		,edition
	)
	SELECT
		IFNULL(MAX(Id), 0) +1
		,'#{Type}'
		,#{size}
		,1
		,#{size}
	FROM ${BaseSystem}TableKey`
	sql = strings.Replace(sql, "${BaseSystem}", sDbName, -1)
	sql = strings.Replace(sql, "#{size}", stringutil.ToStr(size), -1)
	sql = strings.Replace(sql, "#{Type}", serieName, -1)

	dbResult := gorm.Exec(sql)
	if dbResult.Error != nil {
		Log.Error("更新数据发生异常:", dbResult.Error)
		return 0
	}

	return integerutil.ToInt(dbResult.RowsAffected, 0)
}

/**
 * 重置
 * @param serieName
 * @return
 */
func (dao TableKeyDao) reset(serieName string) int {
	sql := `UPDATE ${BaseSystem}TableKey SET
			Value = 1
			,edition = (edition +1)
		WHERE Type = '#{Type}'`
	sql = strings.Replace(sql, "${BaseSystem}", sDbName, -1)
	sql = strings.Replace(sql, "#{Type}", serieName, -1)

	dbResult := gorm.Exec(sql)
	if dbResult.Error != nil {
		Log.Error("更新数据发生异常:", dbResult.Error)
		return 0
	}

	return integerutil.ToInt(dbResult.RowsAffected, 0)
}
